package com.ec50n9.server.module.resource

import com.ec50n9.server.common.mayBeAlreadyExist
import com.ec50n9.server.common.mayBeNotFound
import com.ec50n9.server.module.common.renderTo
import com.ec50n9.server.module.role.RoleQueryRendered
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Service
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import java.util.*

interface ResourceRepository: CrudRepository<Resource, String> {
    fun findByCode(code: String): Optional<Resource>
    fun findByCodeIn(codes: Collection<String>): List<Resource>
    fun findByStatus(status: Int): List<Resource>
}

@Service
class ResourceService(private val resourceRepository: ResourceRepository) {
    private val name = "资源"

    fun findOne(code: String): Resource = mayBeNotFound(name) {
        resourceRepository.findByCode(code).orElseThrow()
    }

    fun findAll(): Iterable<Resource> = resourceRepository.findAll()

    fun newOne(resource: Resource) = mayBeAlreadyExist(name) {
        resourceRepository.save(resource)
    }

    fun update(resource: Resource) = resourceRepository.save(resource)

    fun delete(resource: Resource) = resourceRepository.delete(resource)
}

@Tag(name = "资源管理")
@RestController
@RequestMapping("/api/resources")
class ResourceController(private val resourceService: ResourceService) {

    @Operation(summary = "获取全部")
    @GetMapping
    fun findAll(): List<ResourceQueryRendered> =
        resourceService.findAll().renderTo(ResourceQueryRendered::class.java)

    @Operation(summary = "通过code获取")
    @GetMapping("/{code}")
    fun findOne(@PathVariable code: String): ResourceQueryRendered =
        resourceService.findOne(code).renderTo(ResourceQueryRendered::class.java)

    @Operation(summary = "获取角色列表")
    @GetMapping("/{code}/roles")
    fun getRoles(@PathVariable code: String): List<RoleQueryRendered> =
        resourceService.findOne(code).roles.renderTo(RoleQueryRendered::class.java)

    @Operation(summary = "新建")
    @PostMapping
    fun newOne(@RequestBody @Validated createForm: ResourceCreateForm): ResourceQueryRendered =
        resourceService.newOne(createForm.renderTo()).renderTo(ResourceQueryRendered::class.java)

    @Operation(summary = "更新")
    @PatchMapping("/{code}")
    fun update(@RequestBody updateForm: ResourceUpdateForm, @PathVariable code: String): ResourceQueryRendered {
        val resource = resourceService.findOne(code)
        updateForm.renderTo(resource)
        return resourceService.update(resource).renderTo(ResourceQueryRendered::class.java)
    }

    @Operation(summary = "删除")
    @DeleteMapping("/{code}")
    fun delete(@PathVariable code: String) = with(resourceService){
        delete(findOne(code))
    }
}